package com.ac.scum.log.task.face.log.counsumer.stages;

import com.ac.common.core.id.SnowflakeIdGenerator;
import com.ac.scum.log.bean.Player;
import com.ac.scum.log.bean.ServerFTPLogKill;
import com.ac.scum.log.task.cons.TaskConst;
import com.ac.scum.log.task.face.log.counsumer.LogConsumer;
import com.ac.scum.log.task.mapper.log.ServerFTPLogKillMapper;
import com.ac.scum.log.task.utils.map.GameMapZoneUtil;
import com.ac.scum.log.task.utils.queue.FTPQueueItem;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import io.micrometer.common.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
@AllArgsConstructor
public class KillLogConsumer implements LogConsumer {
    private final GameMapZoneUtil gameMapZoneUtil;
    private final StringRedisTemplate stringRedisTemplate;
    private final SnowflakeIdGenerator snowflakeIdGenerator;
    private final ServerFTPLogKillMapper serverFTPLogKillMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public void consumerLog(FTPQueueItem ftpQueueItem) {
        try {
            writeAllPlayerInfoInCache(ftpQueueItem);
            String regex = "(\\d{4}\\.\\d{2}\\.\\d{2}-\\d{2}\\.\\d{2}\\.\\d{2}): (.+)";
            Pattern pattern = Pattern.compile(regex);
            List<ServerFTPLogKill> killList = Lists.newArrayList();
            DecimalFormat format = new DecimalFormat("#.00");

            for (GameLogLine line : splitLine(ftpQueueItem)) {
                String lineContext = line.getLineContext();
                Matcher matcher = pattern.matcher(lineContext);
                if (matcher.find()) {
                    String serverTime = matcher.group(1);
                    String jsonContent = matcher.group(2);
                    try {
                        JSONObject jsonObject = JSON.parseObject(jsonContent);
                        JSONObject killerJsonObject = jsonObject.getJSONObject("Killer");
                        JSONObject killerServerLocation = killerJsonObject.getJSONObject("ServerLocation");
                        Double killer_x = killerServerLocation.getDouble("X");
                        Double killer_y = killerServerLocation.getDouble("Y");
                        Double killer_z = killerServerLocation.getDouble("Z");
                        JSONObject victimJsonObject = jsonObject.getJSONObject("Victim");
                        JSONObject victimServerLocation = victimJsonObject.getJSONObject("ServerLocation");
                        Double victim_x = victimServerLocation.getDouble("X");
                        Double victim_y = victimServerLocation.getDouble("Y");
                        Double victim_z = victimServerLocation.getDouble("Z");
                        ServerFTPLogKill logKill = new ServerFTPLogKill();
                        logKill.setId(snowflakeIdGenerator.nextId());
                        logKill.setFileId(ftpQueueItem.getFileId());
                        logKill.setServerId(ftpQueueItem.getServer().getId());
                        logKill.setLineStart(line.getStartByte());
                        logKill.setLineEnd(line.getEndByte());
                        logKill.setServerTime(parseTimestamp(serverTime, ftpQueueItem));
                        logKill.setType(killerJsonObject.getBoolean("IsInGameEvent") ? 1 : 2);
                        logKill.setKillerHasImmortality(killerJsonObject.getBoolean("HasImmortality") ? 1 : 0);
                        logKill.setKillerLocation(killer_x + "," + killer_y + "," + killer_z);
                        logKill.setKillerLocationZone(gameMapZoneUtil.getZone(killer_x, killer_y));
                        if (killerJsonObject.getLong("UserId") > 0) {
                            logKill.setKillerSteamId(killerJsonObject.getLong("UserId"));
                            Player killer = getOrInsertPlayerServer(logKill.getKillerSteamId(), logKill.getServerId(), killerJsonObject.getString("ProfileName"));
                            logKill.setKillerPlayerId(killer.getId());
                        }
                        if (victimJsonObject.getLong("UserId") > 0) {
                            logKill.setVictimSteamId(victimJsonObject.getLong("UserId"));
                            Player victim = getOrInsertPlayerServer(logKill.getVictimSteamId(), logKill.getServerId(), victimJsonObject.getString("ProfileName"));
                            logKill.setVictimId(victim.getId());
                        }
                        logKill.setVictimLocation(victim_x + "," + victim_y + "," + victim_z);
                        logKill.setVictimLocationZone(gameMapZoneUtil.getZone(victim_x, victim_y));


                        logKill.setWeapon(jsonObject.getString("Weapon"));
                        logKill.setTimeOfDay(jsonObject.getString("TimeOfDay"));
                        if (killer_x == 0.0 && killer_y == 0.0 && killer_z == 0.0 || victim_x == 0.0 && victim_y == 0.0 && victim_z == 0.0) {
                            logKill.setDistance(0.0D);
                        } else {
                            logKill.setDistance(Double.parseDouble(format.format(calculateDistance(killer_x, killer_y, killer_z, victim_x, victim_y, victim_z))));
                        }
                        logKill.setCreateTime(LocalDateTime.now());
                        String result = modifyTarget(logKill.getWeapon());
                        if (StringUtils.isNotBlank(result)) {
                            Object cnWeapon = stringRedisTemplate.opsForHash().get(TaskConst.LOG_CONVERT_KEY_MAP_CACHE, result.toLowerCase());
                            if (cnWeapon != null) {
                                logKill.setWeapon(assembleKillType(logKill.getWeapon().replace(result, (String) cnWeapon)));
                            }
                        }
                        killList.add(logKill);

                        if (logKill.getType() == 2) {
                            redisTemplate.opsForList().rightPush("kills-score:" + logKill.getServerId() + "-" + logKill.getKillerPlayerId() + "-" + logKill.getKillerSteamId(), 1);
                            redisTemplate.opsForList().rightPush("dies-score:" + logKill.getServerId() + "-" + logKill.getVictimId() + "-" + logKill.getVictimSteamId(), -1);
                        }

                    } catch (JSONException ignored) {
                    }
                }
            }
            killList.forEach(serverFTPLogKillMapper::insert);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private static String assembleKillType(String weapon) {
        return weapon.replace("Melee", "近战击杀").replace("Explosion", "爆炸击杀").replace("Projectile", "射击击杀").replace("Point", "陷阱击杀");
    }

    private static double calculateDistance(double x1, double y1, double z1, double x2, double y2, double z2) {
        return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)) * 0.01;
    }

    public static String modifyTarget(String target) {
        int lastUnderscoreIndex = target.lastIndexOf("_");
        if (lastUnderscoreIndex != -1) {
            return target.substring(0, lastUnderscoreIndex);
        }
        return target;
    }
}
